<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2020/9/16
 * Time: 16:58
 */
namespace App\Http\Controllers\Home;
use App\Common\Utils;
use App\Http\Controllers\Controller;
use App\Models\Goods;
use App\Models\Orders;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Log;
use Exception;
class MiaoshaController extends Controller{
    //排队人数
    private $listNumber = 50;
    /*
     * 实现秒杀
     */
    public function secondsKill(Request $request)
    {
        try {
            $user_data = $request->only(['user_id', 'goods_id']);
            if ( !$user_data ) {
                return $this->ajaxReturn(1,'数据不能为空');
            }
            $goodsId = $user_data['goods_id'];
//            $userId = $user_data['user_id'];
            $userId = rand(1,999);
            #访问用户入队接口
            $user_list = $this->requestUser($userId);
            if ( !$user_list ) {
                return $this->ajaxReturn(1,'排队数大于商品总数:'.Redis::llen('user_list'));
            }
            #消费商品,从队列中取出商品
            $count = Redis::lpop('goods_store:' . $goodsId);
            if(!$count) {
                return $this->ajaxReturn(1,'商品抢光了');
            }
            #进入redis锁
            $redisLock = new RedisLockController($userId);
            $lock = $redisLock->lock();
            $logArr['user_id'] = $userId;
            $logArr['count'] = $count;
            $logArr['lock'] = $lock;
            if ($lock) {
                #最后进入数据库操作(每次固定消费1个)
                $mysql_data = $this->storeOrder($userId, $count, '1');
                if ( !$mysql_data ) {
                    Log::info('生成订单失败',$logArr);
                    $redisLock->unlock();
                    return $this->ajaxReturn(1,'生成订单失败');
                } else {
                    #关闭锁
                    Log::info('生成订单成功',$logArr);
                    $redisLock->unlock();
                    return $this->ajaxReturn(0,'抢购成功');
                }
            }
            Log::info('生成订单失败123',$logArr);
            return $this->ajaxReturn(1,'生成订单失败123');

        } catch (Exception $e) {
            throw $e;
        }
    }

    /*
     *下单
     */
    private function storeOrder($user_id, $goods_id, $number)
    {
        try {
            #开启事务
            DB::beginTransaction();
            #查询库存sharedLock()共享锁，可以读取到数据，事务未提交不能修改，直到事务提交
            #lockForUpdate()不能读取到数据
            $resutl = Goods::where(['id'=>$goods_id])->lockForUpdate()->first();
            #添加订单
            if ( $resutl ) {
                $resutl_order = Orders::create([
                    'user_id' => $user_id,
                    'goods_id' => $goods_id,
                    'goods_number' => $number,
                    'ordersn' =>Utils::orderSn(),
                    'price' => $resutl->price,
                ]);
                #减少库存
                $resutl_update = Goods::where('id',$goods_id)->where('goods_num', '>', 0)->decrement('goods_num');
                #将用户从队列里面弹出,允许下一个用户进来（先进先出，存的时候用的lpush,所以取应该rpop）
                Redis::rpop('user_list');
                if ($resutl_order->id > 0 && $resutl_update > 0) {
                    DB::commit();
                    return true;
                }
            }

            DB::rollBack();
            return false;

        } catch(Exception $e) {
            throw $e;
        }
    }

    /**
     * 将商品加入redis
     */
    public function storageGoods(Request $request)
    {
        $goodsId = $request->input('goods_id',1);
        try {
            #查询商品
            $resutl = Goods::where('id', $goodsId)->first();
            $store = $resutl->goods_num;
            $res = Redis::llen('goods_store:' . $resutl->id);
            $count = $store - $res;
            if($count > 0){
                for($i = 0;$i < $count; $i++){
                    Redis::lpush('goods_store:' . $resutl['id'], $resutl['id']);
                }
            }
        } catch (Exception $e) {
           return $this->ajaxReturn(1,$e->getMessage());
        }
        return $this->ajaxReturn(0,'商品加入redis成功');
    }

    /*
     *
     * 将用户也存入队列中（就是将访问请求数据）(此处没有进行用户过滤，同一个用户进行多次请求也会进入队列)
     */
    private function requestUser($userId)
    {
        $res = Redis::llen('user_list');
        #判断排队数
        if ($res = Redis::llen('user_list') > $this->listNumber) {
            // return '排队数大于商品总数';
            return false;
        }
        #添加数据
        Redis::lpush('user_list', $userId);
        return true;
    }


}